package org.visionlibrary.image.filters.bluring;

import java.awt.Point;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.model.WindowFilter;


public class Kuwahara extends WindowFilter {
	protected int width = 5;
	protected int height = 5;

	public Kuwahara(int width, int height) {
		this.width = width;
		this.height = height;
	}

	public Kuwahara(int dimmension) {
		this(dimmension, dimmension);
	}

	public Kuwahara() {
		this(5); // the smallest possible window
	}

	@Override
	protected int getNewPixelVal(TiledImage src, Point p, int channel) {
		int cx = windowWidth / 2;
		int cy = windowHeight / 2;

		// example for window 5x5,
		// A, B, C, D - indicators of regions in window
		// 0 1 2 3 4
		// 0 A A AB B B
		// 1 A A AB B B
		// 2 AC AC ABCD BD BD
		// 3 C C CD D D
		// 4 C C CD D D

		int n = 0; // elements in window

		int sumA = 0; // sum for region A
		int varA = 0; // sum for variance for region A
		// calculation for region A
		for (int x = 0; x <= cx; x++) {
			for (int y = 0; y <= cy; y++) {
				Point tmpp = new Point(x, y);
				int val = getWindowPixelVal(src, tmpp, channel);
				sumA += val;
				varA += val * val;
				n++; // we increment counter
			}
		}

		int sumB = 0;// sum for region B
		int varB = 0;// sum for variance for region B
		// calculation for region B
		for (int x = cx; x < windowWidth; x++) {
			for (int y = 0; y <= cy; y++) {
				Point tmpp = new Point(x, y);
				int val = getWindowPixelVal(src, tmpp, channel);
				sumB += val;
				varB += val * val;
			}
		}

		int sumC = 0;// sum for region C
		int varC = 0;// sum for variance for region C
		// calculation for region C
		for (int x = 0; x < cx; x++) {
			for (int y = cy; y < windowHeight; y++) {
				Point tmpp = new Point(x, y);
				int val = getWindowPixelVal(src, tmpp, channel);
				sumC += val;
				varC += val * val;
			}
		}

		int sumD = 0;// sum for region D
		int varD = 0;// sum for variance for region D
		// calculation for region D
		for (int x = cx; x < windowWidth; x++) {
			for (int y = cy; y < windowHeight; y++) {
				Point tmpp = new Point(x, y);
				int val = getWindowPixelVal(src, tmpp, channel);
				sumD += val;
				varD += val * val;
			}
		}

		int[] mean = new int[4]; // we have only four regions
		int[] variance = new int[4];

		mean[0] = sumA / n;
		variance[0] = (n * varA - sumA * sumA) / n;

		mean[1] = sumB / n;
		variance[1] = (n * varB - sumB * sumB) / n;

		mean[2] = sumC / n;
		variance[2] = (n * varC - sumC * sumC) / n;

		mean[3] = sumD / n;
		variance[3] = (n * varD - sumD * sumD) / n;

		// we must find the smallest variance
		// we return the mean of the region with the smallest variance

		int i = 0;
		int v = variance[0];
		if (v > variance[1]) {
			i = 1; // we found that variance stored in element 1 of the table is
					// lower than variance
			v = variance[1]; // stored in element 0, we remember index and we
								// asign new value to variable v
		}
		if (v > variance[2]) {
			i = 2;
			v = variance[2];
		}
		if (v > variance[3]) {
			i = 3;
		}

		return mean[i];
	}

	@Override
	protected void setWindowProperties() {
		windowWidth = width;
		windowHeight = height;
		dstPointInWindow = new Point(width / 2, height / 2);
	}
}
